﻿// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// Microsoft Public License (MS-PL)
// 
// This license governs use of the accompanying software. If you use the
// software, you accept this license. If you do not accept the license, do not
// use the software.
// 
// 1. Definitions
// 
//   The terms "reproduce," "reproduction," "derivative works," and
//   "distribution" have the same meaning here as under U.S. copyright law. A
//   "contribution" is the original software, or any additions or changes to
//   the software. A "contributor" is any person that distributes its
//   contribution under this license. "Licensed patents" are a contributor's
//   patent claims that read directly on its contribution.
// 
// 2. Grant of Rights
// 
//   (A) Copyright Grant- Subject to the terms of this license, including the
//       license conditions and limitations in section 3, each contributor
//       grants you a non-exclusive, worldwide, royalty-free copyright license
//       to reproduce its contribution, prepare derivative works of its
//       contribution, and distribute its contribution or any derivative works
//       that you create.
// 
//   (B) Patent Grant- Subject to the terms of this license, including the
//       license conditions and limitations in section 3, each contributor
//       grants you a non-exclusive, worldwide, royalty-free license under its
//       licensed patents to make, have made, use, sell, offer for sale,
//       import, and/or otherwise dispose of its contribution in the software
//       or derivative works of the contribution in the software.
// 
// 3. Conditions and Limitations
// 
//   (A) No Trademark License- This license does not grant you rights to use
//       any contributors' name, logo, or trademarks.
// 
//   (B) If you bring a patent claim against any contributor over patents that
//       you claim are infringed by the software, your patent license from such
//       contributor to the software ends automatically.
// 
//   (C) If you distribute any portion of the software, you must retain all
//       copyright, patent, trademark, and attribution notices that are present
//       in the software.
// 
//   (D) If you distribute any portion of the software in source code form, you
//       may do so only under this license by including a complete copy of this
//       license with your distribution. If you distribute any portion of the
//       software in compiled or object code form, you may only do so under a
//       license that complies with this license.
// 
//   (E) The software is licensed "as-is." You bear the risk of using it. The
//       contributors give no express warranties, guarantees or conditions. You
//       may have additional consumer rights under your local laws which this
//       license cannot change. To the extent permitted under your local laws,
//       the contributors exclude the implied warranties of merchantability,
//       fitness for a particular purpose and non-infringement.
//       




#pragma once

//-----------------------------------------------------------------------------
// macros
//-----------------------------------------------------------------------------

#define DEFINE_CALLBACK_MANAGER(NAME, TYPE) \
    DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, NullMutex)

#define DEFINE_CONCURRENT_CALLBACK_MANAGER(NAME, TYPE) \
    DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, RecursiveMutex)

#define DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, CALLBACK_TYPE, MUTEX_TYPE) \
    struct NAME##CallbackTraits: public CallbackTraits<NAME##CallbackTraits, CALLBACK_TYPE, MUTEX_TYPE> {};

#define CALLBACK_MANAGER(NAME) \
    CallbackManager<NAME##CallbackTraits>

//-----------------------------------------------------------------------------
// CallbackTraits
//-----------------------------------------------------------------------------

template <typename TTraits, typename TCallback, typename TMutex>
class CallbackTraits
{
    PROHIBIT_CONSTRUCT(CallbackTraits)

public:

    typedef TCallback CallbackT;

    template <typename TResult>
    static TResult CallWithLock(const function<TResult()>& function)
    {
        BEGIN_MUTEX_SCOPE(*ms_pMutex)

            return function();

        END_MUTEX_SCOPE
    }

private:

    // Put the mutex on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static TMutex* ms_pMutex;
};

template <typename TTraits, typename TCallback, typename TMutex>
TMutex* CallbackTraits<TTraits, TCallback, TMutex>::ms_pMutex = new TMutex;

//-----------------------------------------------------------------------------
// CallbackSlot (unused)
//-----------------------------------------------------------------------------

template <typename TTraits, size_t NIndex, typename TCallback>
class CallbackSlot
{
    PROHIBIT_CONSTRUCT(CallbackSlot)
};

//-----------------------------------------------------------------------------
// CallbackSlot specializations
//-----------------------------------------------------------------------------


template <typename TTraits, size_t NIndex, typename TResult>
class CallbackSlot<TTraits, NIndex, TResult()>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT();
    typedef function<CallbackT> FunctionT;

    static TResult Callback()
    {
        return GetFunctionWithLock()();
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult>
function<TResult()>* CallbackSlot<TTraits, NIndex, TResult()>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0>
class CallbackSlot<TTraits, NIndex, TResult(T0)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0)
    {
        return GetFunctionWithLock()(a0);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0>
function<TResult(T0)>* CallbackSlot<TTraits, NIndex, TResult(T0)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1)
    {
        return GetFunctionWithLock()(a0, a1);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1>
function<TResult(T0, T1)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2)
    {
        return GetFunctionWithLock()(a0, a1, a2);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2>
function<TResult(T0, T1, T2)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3>
function<TResult(T0, T1, T2, T3)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4>
function<TResult(T0, T1, T2, T3, T4)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
function<TResult(T0, T1, T2, T3, T4, T5)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
function<TResult(T0, T1, T2, T3, T4, T5, T6)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, T14 a14)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)>::ms_pFunction = nullptr;

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
class CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>
{
    PROHIBIT_CONSTRUCT(CallbackSlot)

public:

    typedef TResult CallbackT(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
    typedef function<CallbackT> FunctionT;

    static TResult Callback(T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, T14 a14, T15 a15)
    {
        return GetFunctionWithLock()(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
    }

    static FunctionT GetFunctionWithLock()
    {
        return TTraits::CallWithLock<FunctionT>([]
        {
            return GetFunction();
        });
    }

    static void SetFunctionWithLock(const FunctionT& function)
    {
        TTraits::CallWithLock<void>([&function]
        {
            SetFunction(function);
        });
    }

    static FunctionT GetFunction()
    {
        return (ms_pFunction != nullptr) ? *ms_pFunction : nullptr;
    }

    static void SetFunction(const FunctionT& function)
    {
        if (ms_pFunction != nullptr)
        {
            delete ms_pFunction;
        }

        ms_pFunction = new FunctionT(function);
    }

    static bool HasFunction()
    {
        return (ms_pFunction != nullptr) ? static_cast<bool>(*ms_pFunction) : false;
    }

private:

    // Put the functor on the heap. At process shutdown, static cleanup races against GC,
    // so using non-POD static data in conjunction with managed objects is problematic.

    static FunctionT* ms_pFunction;
};

template <typename TTraits, size_t NIndex, typename TResult, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
function<TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>* CallbackSlot<TTraits, NIndex, TResult(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>::ms_pFunction = nullptr;

//-----------------------------------------------------------------------------
// CallbackManager
//-----------------------------------------------------------------------------

template <typename TTraits>
class CallbackManager
{
    PROHIBIT_CONSTRUCT(CallbackManager)

public:

    typedef typename TTraits::CallbackT CallbackT;
    typedef function<CallbackT> FunctionT;

    static CallbackT* Alloc(const FunctionT& function)
    {
        return TTraits::CallWithLock<CallbackT*>([&function]
        {
            
            if (!HasFunction<0>())
            {
                SetFunction<0>(function);
                return GetCallback<0>();
            }
            
            if (!HasFunction<1>())
            {
                SetFunction<1>(function);
                return GetCallback<1>();
            }
            
            if (!HasFunction<2>())
            {
                SetFunction<2>(function);
                return GetCallback<2>();
            }
            
            if (!HasFunction<3>())
            {
                SetFunction<3>(function);
                return GetCallback<3>();
            }
            
            if (!HasFunction<4>())
            {
                SetFunction<4>(function);
                return GetCallback<4>();
            }
            
            if (!HasFunction<5>())
            {
                SetFunction<5>(function);
                return GetCallback<5>();
            }
            
            if (!HasFunction<6>())
            {
                SetFunction<6>(function);
                return GetCallback<6>();
            }
            
            if (!HasFunction<7>())
            {
                SetFunction<7>(function);
                return GetCallback<7>();
            }
            
            if (!HasFunction<8>())
            {
                SetFunction<8>(function);
                return GetCallback<8>();
            }
            
            if (!HasFunction<9>())
            {
                SetFunction<9>(function);
                return GetCallback<9>();
            }
            
            if (!HasFunction<10>())
            {
                SetFunction<10>(function);
                return GetCallback<10>();
            }
            
            if (!HasFunction<11>())
            {
                SetFunction<11>(function);
                return GetCallback<11>();
            }
            
            if (!HasFunction<12>())
            {
                SetFunction<12>(function);
                return GetCallback<12>();
            }
            
            if (!HasFunction<13>())
            {
                SetFunction<13>(function);
                return GetCallback<13>();
            }
            
            if (!HasFunction<14>())
            {
                SetFunction<14>(function);
                return GetCallback<14>();
            }
            
            if (!HasFunction<15>())
            {
                SetFunction<15>(function);
                return GetCallback<15>();
            }
            
            if (!HasFunction<16>())
            {
                SetFunction<16>(function);
                return GetCallback<16>();
            }
            
            if (!HasFunction<17>())
            {
                SetFunction<17>(function);
                return GetCallback<17>();
            }
            
            if (!HasFunction<18>())
            {
                SetFunction<18>(function);
                return GetCallback<18>();
            }
            
            if (!HasFunction<19>())
            {
                SetFunction<19>(function);
                return GetCallback<19>();
            }
            
            if (!HasFunction<20>())
            {
                SetFunction<20>(function);
                return GetCallback<20>();
            }
            
            if (!HasFunction<21>())
            {
                SetFunction<21>(function);
                return GetCallback<21>();
            }
            
            if (!HasFunction<22>())
            {
                SetFunction<22>(function);
                return GetCallback<22>();
            }
            
            if (!HasFunction<23>())
            {
                SetFunction<23>(function);
                return GetCallback<23>();
            }
            
            if (!HasFunction<24>())
            {
                SetFunction<24>(function);
                return GetCallback<24>();
            }
            
            if (!HasFunction<25>())
            {
                SetFunction<25>(function);
                return GetCallback<25>();
            }
            
            if (!HasFunction<26>())
            {
                SetFunction<26>(function);
                return GetCallback<26>();
            }
            
            if (!HasFunction<27>())
            {
                SetFunction<27>(function);
                return GetCallback<27>();
            }
            
            if (!HasFunction<28>())
            {
                SetFunction<28>(function);
                return GetCallback<28>();
            }
            
            if (!HasFunction<29>())
            {
                SetFunction<29>(function);
                return GetCallback<29>();
            }
            
            if (!HasFunction<30>())
            {
                SetFunction<30>(function);
                return GetCallback<30>();
            }
            
            if (!HasFunction<31>())
            {
                SetFunction<31>(function);
                return GetCallback<31>();
            }
            
            if (!HasFunction<32>())
            {
                SetFunction<32>(function);
                return GetCallback<32>();
            }
            
            if (!HasFunction<33>())
            {
                SetFunction<33>(function);
                return GetCallback<33>();
            }
            
            if (!HasFunction<34>())
            {
                SetFunction<34>(function);
                return GetCallback<34>();
            }
            
            if (!HasFunction<35>())
            {
                SetFunction<35>(function);
                return GetCallback<35>();
            }
            
            if (!HasFunction<36>())
            {
                SetFunction<36>(function);
                return GetCallback<36>();
            }
            
            if (!HasFunction<37>())
            {
                SetFunction<37>(function);
                return GetCallback<37>();
            }
            
            if (!HasFunction<38>())
            {
                SetFunction<38>(function);
                return GetCallback<38>();
            }
            
            if (!HasFunction<39>())
            {
                SetFunction<39>(function);
                return GetCallback<39>();
            }
            
            if (!HasFunction<40>())
            {
                SetFunction<40>(function);
                return GetCallback<40>();
            }
            
            if (!HasFunction<41>())
            {
                SetFunction<41>(function);
                return GetCallback<41>();
            }
            
            if (!HasFunction<42>())
            {
                SetFunction<42>(function);
                return GetCallback<42>();
            }
            
            if (!HasFunction<43>())
            {
                SetFunction<43>(function);
                return GetCallback<43>();
            }
            
            if (!HasFunction<44>())
            {
                SetFunction<44>(function);
                return GetCallback<44>();
            }
            
            if (!HasFunction<45>())
            {
                SetFunction<45>(function);
                return GetCallback<45>();
            }
            
            if (!HasFunction<46>())
            {
                SetFunction<46>(function);
                return GetCallback<46>();
            }
            
            if (!HasFunction<47>())
            {
                SetFunction<47>(function);
                return GetCallback<47>();
            }
            
            if (!HasFunction<48>())
            {
                SetFunction<48>(function);
                return GetCallback<48>();
            }
            
            if (!HasFunction<49>())
            {
                SetFunction<49>(function);
                return GetCallback<49>();
            }
            
            if (!HasFunction<50>())
            {
                SetFunction<50>(function);
                return GetCallback<50>();
            }
            
            if (!HasFunction<51>())
            {
                SetFunction<51>(function);
                return GetCallback<51>();
            }
            
            if (!HasFunction<52>())
            {
                SetFunction<52>(function);
                return GetCallback<52>();
            }
            
            if (!HasFunction<53>())
            {
                SetFunction<53>(function);
                return GetCallback<53>();
            }
            
            if (!HasFunction<54>())
            {
                SetFunction<54>(function);
                return GetCallback<54>();
            }
            
            if (!HasFunction<55>())
            {
                SetFunction<55>(function);
                return GetCallback<55>();
            }
            
            if (!HasFunction<56>())
            {
                SetFunction<56>(function);
                return GetCallback<56>();
            }
            
            if (!HasFunction<57>())
            {
                SetFunction<57>(function);
                return GetCallback<57>();
            }
            
            if (!HasFunction<58>())
            {
                SetFunction<58>(function);
                return GetCallback<58>();
            }
            
            if (!HasFunction<59>())
            {
                SetFunction<59>(function);
                return GetCallback<59>();
            }
            
            if (!HasFunction<60>())
            {
                SetFunction<60>(function);
                return GetCallback<60>();
            }
            
            if (!HasFunction<61>())
            {
                SetFunction<61>(function);
                return GetCallback<61>();
            }
            
            if (!HasFunction<62>())
            {
                SetFunction<62>(function);
                return GetCallback<62>();
            }
            
            if (!HasFunction<63>())
            {
                SetFunction<63>(function);
                return GetCallback<63>();
            }
            
            return static_cast<CallbackT*>(nullptr);
        });
    }

    static bool Free(CallbackT* pCallback)
    {
        return TTraits::CallWithLock<bool>([pCallback]
        {
            
            if (pCallback == GetCallback<0>())
            {
                _ASSERTE(HasFunction<0>());
                SetFunction<0>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<1>())
            {
                _ASSERTE(HasFunction<1>());
                SetFunction<1>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<2>())
            {
                _ASSERTE(HasFunction<2>());
                SetFunction<2>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<3>())
            {
                _ASSERTE(HasFunction<3>());
                SetFunction<3>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<4>())
            {
                _ASSERTE(HasFunction<4>());
                SetFunction<4>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<5>())
            {
                _ASSERTE(HasFunction<5>());
                SetFunction<5>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<6>())
            {
                _ASSERTE(HasFunction<6>());
                SetFunction<6>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<7>())
            {
                _ASSERTE(HasFunction<7>());
                SetFunction<7>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<8>())
            {
                _ASSERTE(HasFunction<8>());
                SetFunction<8>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<9>())
            {
                _ASSERTE(HasFunction<9>());
                SetFunction<9>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<10>())
            {
                _ASSERTE(HasFunction<10>());
                SetFunction<10>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<11>())
            {
                _ASSERTE(HasFunction<11>());
                SetFunction<11>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<12>())
            {
                _ASSERTE(HasFunction<12>());
                SetFunction<12>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<13>())
            {
                _ASSERTE(HasFunction<13>());
                SetFunction<13>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<14>())
            {
                _ASSERTE(HasFunction<14>());
                SetFunction<14>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<15>())
            {
                _ASSERTE(HasFunction<15>());
                SetFunction<15>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<16>())
            {
                _ASSERTE(HasFunction<16>());
                SetFunction<16>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<17>())
            {
                _ASSERTE(HasFunction<17>());
                SetFunction<17>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<18>())
            {
                _ASSERTE(HasFunction<18>());
                SetFunction<18>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<19>())
            {
                _ASSERTE(HasFunction<19>());
                SetFunction<19>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<20>())
            {
                _ASSERTE(HasFunction<20>());
                SetFunction<20>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<21>())
            {
                _ASSERTE(HasFunction<21>());
                SetFunction<21>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<22>())
            {
                _ASSERTE(HasFunction<22>());
                SetFunction<22>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<23>())
            {
                _ASSERTE(HasFunction<23>());
                SetFunction<23>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<24>())
            {
                _ASSERTE(HasFunction<24>());
                SetFunction<24>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<25>())
            {
                _ASSERTE(HasFunction<25>());
                SetFunction<25>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<26>())
            {
                _ASSERTE(HasFunction<26>());
                SetFunction<26>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<27>())
            {
                _ASSERTE(HasFunction<27>());
                SetFunction<27>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<28>())
            {
                _ASSERTE(HasFunction<28>());
                SetFunction<28>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<29>())
            {
                _ASSERTE(HasFunction<29>());
                SetFunction<29>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<30>())
            {
                _ASSERTE(HasFunction<30>());
                SetFunction<30>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<31>())
            {
                _ASSERTE(HasFunction<31>());
                SetFunction<31>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<32>())
            {
                _ASSERTE(HasFunction<32>());
                SetFunction<32>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<33>())
            {
                _ASSERTE(HasFunction<33>());
                SetFunction<33>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<34>())
            {
                _ASSERTE(HasFunction<34>());
                SetFunction<34>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<35>())
            {
                _ASSERTE(HasFunction<35>());
                SetFunction<35>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<36>())
            {
                _ASSERTE(HasFunction<36>());
                SetFunction<36>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<37>())
            {
                _ASSERTE(HasFunction<37>());
                SetFunction<37>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<38>())
            {
                _ASSERTE(HasFunction<38>());
                SetFunction<38>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<39>())
            {
                _ASSERTE(HasFunction<39>());
                SetFunction<39>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<40>())
            {
                _ASSERTE(HasFunction<40>());
                SetFunction<40>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<41>())
            {
                _ASSERTE(HasFunction<41>());
                SetFunction<41>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<42>())
            {
                _ASSERTE(HasFunction<42>());
                SetFunction<42>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<43>())
            {
                _ASSERTE(HasFunction<43>());
                SetFunction<43>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<44>())
            {
                _ASSERTE(HasFunction<44>());
                SetFunction<44>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<45>())
            {
                _ASSERTE(HasFunction<45>());
                SetFunction<45>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<46>())
            {
                _ASSERTE(HasFunction<46>());
                SetFunction<46>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<47>())
            {
                _ASSERTE(HasFunction<47>());
                SetFunction<47>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<48>())
            {
                _ASSERTE(HasFunction<48>());
                SetFunction<48>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<49>())
            {
                _ASSERTE(HasFunction<49>());
                SetFunction<49>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<50>())
            {
                _ASSERTE(HasFunction<50>());
                SetFunction<50>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<51>())
            {
                _ASSERTE(HasFunction<51>());
                SetFunction<51>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<52>())
            {
                _ASSERTE(HasFunction<52>());
                SetFunction<52>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<53>())
            {
                _ASSERTE(HasFunction<53>());
                SetFunction<53>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<54>())
            {
                _ASSERTE(HasFunction<54>());
                SetFunction<54>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<55>())
            {
                _ASSERTE(HasFunction<55>());
                SetFunction<55>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<56>())
            {
                _ASSERTE(HasFunction<56>());
                SetFunction<56>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<57>())
            {
                _ASSERTE(HasFunction<57>());
                SetFunction<57>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<58>())
            {
                _ASSERTE(HasFunction<58>());
                SetFunction<58>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<59>())
            {
                _ASSERTE(HasFunction<59>());
                SetFunction<59>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<60>())
            {
                _ASSERTE(HasFunction<60>());
                SetFunction<60>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<61>())
            {
                _ASSERTE(HasFunction<61>());
                SetFunction<61>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<62>())
            {
                _ASSERTE(HasFunction<62>());
                SetFunction<62>(nullptr);
                return true;
            }
            
            if (pCallback == GetCallback<63>())
            {
                _ASSERTE(HasFunction<63>());
                SetFunction<63>(nullptr);
                return true;
            }
            
            return false;
        });
    }

private:

    template <size_t NIndex>
    static CallbackT* GetCallback()
    {
        return CallbackSlot<TTraits, NIndex, CallbackT>::Callback;
    }

    template <size_t NIndex>
    static void SetFunction(const FunctionT& function)
    {
        CallbackSlot<TTraits, NIndex, CallbackT>::SetFunction(function);
    }

    template <size_t NIndex>
    static bool HasFunction()
    {
        return CallbackSlot<TTraits, NIndex, CallbackT>::HasFunction();
    }
};
